<?php
/**
 * 自动修复引擎和备份机制
 * Auto Fix Engine and Backup System
 * 
 * @package WP Bootstrap Woo
 */

if (!defined('ABSPATH')) {
    exit; // 禁止直接访问
}

/**
 * 自动修复引擎类
 * Auto Fix Engine Class
 */
class WBW_Auto_Fix_Engine {
    
    /**
     * 备份目录
     */
    private $backup_dir;
    
    /**
     * 修复结果
     */
    private $fix_results = array();
    
    /**
     * 支持的修复类型
     */
    private $supported_fixes = array(
        'missing_semicolon',     // 缺少分号
        'unmatched_brackets',    // 括号不匹配
        'quote_mismatch',        // 引号错误
        'undefined_variable',    // 未定义变量
        'deprecated_function',   // 弃用函数
        'parse_error',          // 解析错误
        'syntax_error'          // 语法错误
    );
    
    /**
     * 构造函数
     */
    public function __construct() {
        $this->init_backup_directory();
    }
    
    /**
     * 初始化备份目录
     */
    private function init_backup_directory() {
        $upload_dir = wp_upload_dir();
        $this->backup_dir = $upload_dir['basedir'] . '/theme-backups';
        
        if (!file_exists($this->backup_dir)) {
            wp_mkdir_p($this->backup_dir);
            
            // 创建 .htaccess 文件保护备份目录
            $htaccess_content = "Order deny,allow\nDeny from all\n";
            file_put_contents($this->backup_dir . '/.htaccess', $htaccess_content);
        }
    }
    
    /**
     * 创建文件备份
     * 
     * @param string $file_path 文件路径
     * @return string|false 备份文件路径或失败返回false
     */
    public function create_backup($file_path) {
        if (!file_exists($file_path)) {
            return false;
        }
        
        $file_info = pathinfo($file_path);
        $relative_path = str_replace(get_template_directory(), '', $file_path);
        $backup_subdir = $this->backup_dir . '/' . date('Y-m-d_H-i-s');
        
        if (!file_exists($backup_subdir)) {
            wp_mkdir_p($backup_subdir);
        }
        
        $backup_path = $backup_subdir . $relative_path;
        $backup_dir = dirname($backup_path);
        
        if (!file_exists($backup_dir)) {
            wp_mkdir_p($backup_dir);
        }
        
        if (copy($file_path, $backup_path)) {
            $this->log_backup_creation($file_path, $backup_path);
            return $backup_path;
        }
        
        return false;
    }
    
    /**
     * 批量创建备份
     * 
     * @param array $file_paths 文件路径数组
     * @return array 备份结果
     */
    public function create_batch_backup($file_paths) {
        $backup_results = array();
        $backup_id = date('Y-m-d_H-i-s');
        
        foreach ($file_paths as $file_path) {
            $backup_path = $this->create_file_backup_with_id($file_path, $backup_id);
            $backup_results[$file_path] = $backup_path;
        }
        
        // 创建备份清单
        $this->create_backup_manifest($backup_id, $backup_results);
        
        return $backup_results;
    }
    
    /**
     * 使用指定ID创建文件备份
     * 
     * @param string $file_path 文件路径
     * @param string $backup_id 备份ID
     * @return string|false 备份路径
     */
    private function create_file_backup_with_id($file_path, $backup_id) {
        if (!file_exists($file_path)) {
            return false;
        }
        
        $relative_path = str_replace(get_template_directory(), '', $file_path);
        $backup_subdir = $this->backup_dir . '/' . $backup_id;
        
        if (!file_exists($backup_subdir)) {
            wp_mkdir_p($backup_subdir);
        }
        
        $backup_path = $backup_subdir . $relative_path;
        $backup_dir = dirname($backup_path);
        
        if (!file_exists($backup_dir)) {
            wp_mkdir_p($backup_dir);
        }
        
        if (copy($file_path, $backup_path)) {
            return $backup_path;
        }
        
        return false;
    }
    
    /**
     * 创建备份清单
     * 
     * @param string $backup_id 备份ID
     * @param array $backup_results 备份结果
     */
    private function create_backup_manifest($backup_id, $backup_results) {
        $manifest = array(
            'backup_id' => $backup_id,
            'created_at' => current_time('timestamp'),
            'files' => array()
        );
        
        foreach ($backup_results as $original => $backup) {
            $manifest['files'][] = array(
                'original_path' => $original,
                'backup_path' => $backup,
                'file_size' => file_exists($original) ? filesize($original) : 0,
                'file_hash' => file_exists($original) ? md5_file($original) : ''
            );
        }
        
        $manifest_path = $this->backup_dir . '/' . $backup_id . '/manifest.json';
        file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT));
    }
    
    /**
     * 自动修复文件
     * 
     * @param string $file_path 文件路径
     * @param array $errors 错误信息
     * @return array 修复结果
     */
    public function auto_fix_file($file_path, $errors = array()) {
        // 先创建备份
        $backup_path = $this->create_backup($file_path);
        if (!$backup_path) {
            return array(
                'status' => 'error',
                'message' => '无法创建备份文件',
                'fixes_applied' => array()
            );
        }
        
        $content = file_get_contents($file_path);
        if ($content === false) {
            return array(
                'status' => 'error',
                'message' => '无法读取文件内容',
                'fixes_applied' => array()
            );
        }
        
        $original_content = $content;
        $fixes_applied = array();
        
        // 如果没有提供错误信息，先检查语法
        if (empty($errors)) {
            $errors = $this->detect_syntax_errors($file_path);
        }
        
        // 应用修复规则
        foreach ($errors as $error) {
            $fix_result = $this->apply_fix_rule($content, $error);
            if ($fix_result['applied']) {
                $content = $fix_result['content'];
                $fixes_applied[] = $fix_result['fix_description'];
            }
        }
        
        // 通用修复规则
        $content = $this->apply_general_fixes($content, $fixes_applied);
        
        // 如果内容有变化，保存修复后的文件
        if ($content !== $original_content) {
            if (file_put_contents($file_path, $content) !== false) {
                // 验证修复结果
                $validation_result = $this->validate_fix($file_path);
                
                if ($validation_result['valid']) {
                    return array(
                        'status' => 'success',
                        'message' => '文件修复成功',
                        'backup_path' => $backup_path,
                        'fixes_applied' => $fixes_applied,
                        'validation' => $validation_result
                    );
                } else {
                    // 修复失败，恢复备份
                    copy($backup_path, $file_path);
                    return array(
                        'status' => 'error',
                        'message' => '修复后验证失败，已恢复原文件',
                        'backup_path' => $backup_path,
                        'fixes_attempted' => $fixes_applied,
                        'validation_error' => $validation_result['error']
                    );
                }
            } else {
                return array(
                    'status' => 'error',
                    'message' => '无法保存修复后的文件',
                    'backup_path' => $backup_path
                );
            }
        } else {
            return array(
                'status' => 'no_changes',
                'message' => '未检测到需要修复的问题',
                'backup_path' => $backup_path
            );
        }
    }
    
    /**
     * 检测语法错误
     * 
     * @param string $file_path 文件路径
     * @return array 错误列表
     */
    private function detect_syntax_errors($file_path) {
        $errors = array();
        
        // 使用PHP语法检查
        $output = array();
        $return_var = 0;
        exec("php -l " . escapeshellarg($file_path) . " 2>&1", $output, $return_var);
        
        if ($return_var !== 0) {
            $error_message = implode("\n", $output);
            $line_number = $this->extract_line_number($error_message);
            
            $errors[] = array(
                'type' => $this->classify_error($error_message),
                'message' => $error_message,
                'line' => $line_number,
                'content' => $this->get_file_line($file_path, $line_number)
            );
        }
        
        return $errors;
    }
    
    /**
     * 分类错误类型
     * 
     * @param string $error_message 错误消息
     * @return string 错误类型
     */
    private function classify_error($error_message) {
        if (strpos($error_message, 'unexpected') !== false) {
            if (strpos($error_message, 'expecting') !== false) {
                return 'missing_semicolon';
            }
            return 'syntax_error';
        }
        
        if (strpos($error_message, 'Parse error') !== false) {
            return 'parse_error';
        }
        
        if (strpos($error_message, 'undefined') !== false) {
            return 'undefined_variable';
        }
        
        return 'unknown_error';
    }
    
    /**
     * 应用修复规则
     * 
     * @param string $content 文件内容
     * @param array $error 错误信息
     * @return array 修复结果
     */
    private function apply_fix_rule($content, $error) {
        $lines = explode("\n", $content);
        $line_index = $error['line'] - 1;
        
        if (!isset($lines[$line_index])) {
            return array('applied' => false, 'content' => $content);
        }
        
        $original_line = $lines[$line_index];
        $fixed_line = $original_line;
        $fix_applied = false;
        $fix_description = '';
        
        switch ($error['type']) {
            case 'missing_semicolon':
                $fixed_line = $this->fix_missing_semicolon($original_line);
                if ($fixed_line !== $original_line) {
                    $fix_applied = true;
                    $fix_description = "第{$error['line']}行: 添加缺少的分号";
                }
                break;
                
            case 'unmatched_brackets':
                $fixed_line = $this->fix_unmatched_brackets($original_line);
                if ($fixed_line !== $original_line) {
                    $fix_applied = true;
                    $fix_description = "第{$error['line']}行: 修复不匹配的括号";
                }
                break;
                
            case 'quote_mismatch':
                $fixed_line = $this->fix_quote_mismatch($original_line);
                if ($fixed_line !== $original_line) {
                    $fix_applied = true;
                    $fix_description = "第{$error['line']}行: 修复引号不匹配";
                }
                break;
                
            case 'undefined_variable':
                // 此类错误通常需要手动处理
                $fix_description = "第{$error['line']}行: 检测到未定义变量，需要手动检查";
                break;
        }
        
        if ($fix_applied) {
            $lines[$line_index] = $fixed_line;
            $content = implode("\n", $lines);
        }
        
        return array(
            'applied' => $fix_applied,
            'content' => $content,
            'fix_description' => $fix_description
        );
    }
    
    /**
     * 修复缺少的分号
     * 
     * @param string $line 代码行
     * @return string 修复后的代码行
     */
    private function fix_missing_semicolon($line) {
        $trimmed = rtrim($line);
        
        // 检查是否需要分号
        if (!empty($trimmed) && 
            !in_array(substr($trimmed, -1), array(';', '{', '}', ':', '(')) &&
            !preg_match('/^\s*(if|else|for|while|foreach|switch|class|function|try|catch)/', $trimmed)) {
            
            return $trimmed . ';';
        }
        
        return $line;
    }
    
    /**
     * 修复不匹配的括号
     * 
     * @param string $line 代码行
     * @return string 修复后的代码行
     */
    private function fix_unmatched_brackets($line) {
        $open_brackets = substr_count($line, '(');
        $close_brackets = substr_count($line, ')');
        
        if ($open_brackets > $close_brackets) {
            $line .= str_repeat(')', $open_brackets - $close_brackets);
        } elseif ($close_brackets > $open_brackets) {
            $line = str_repeat('(', $close_brackets - $open_brackets) . $line;
        }
        
        return $line;
    }
    
    /**
     * 修复引号不匹配
     * 
     * @param string $line 代码行
     * @return string 修复后的代码行
     */
    private function fix_quote_mismatch($line) {
        // 检查单引号
        $single_quotes = substr_count($line, "'");
        if ($single_quotes % 2 !== 0) {
            $line .= "'";
        }
        
        // 检查双引号
        $double_quotes = substr_count($line, '"');
        if ($double_quotes % 2 !== 0) {
            $line .= '"';
        }
        
        return $line;
    }
    
    /**
     * 应用通用修复规则
     * 
     * @param string $content 文件内容
     * @param array &$fixes_applied 已应用的修复
     * @return string 修复后的内容
     */
    private function apply_general_fixes($content, &$fixes_applied) {
        // 移除多余的空行
        $original_content = $content;
        $content = preg_replace('/\n\s*\n\s*\n/', "\n\n", $content);
        if ($content !== $original_content) {
            $fixes_applied[] = "移除多余的空行";
        }
        
        // 修复常见的WordPress函数调用错误
        $content = $this->fix_wordpress_function_calls($content, $fixes_applied);
        
        // 修复常见的PHP语法问题
        $content = $this->fix_common_php_issues($content, $fixes_applied);
        
        return $content;
    }
    
    /**
     * 修复WordPress函数调用错误
     * 
     * @param string $content 文件内容
     * @param array &$fixes_applied 已应用的修复
     * @return string 修复后的内容
     */
    private function fix_wordpress_function_calls($content, &$fixes_applied) {
        // 修复常见的WordPress函数名错误
        $wp_fixes = array(
            'get_template_directory_uri(' => 'get_template_directory_uri()',
            'wp_enqueue_script(' => 'wp_enqueue_script(',
            'wp_enqueue_style(' => 'wp_enqueue_style(',
            'add_action(' => 'add_action(',
            'add_filter(' => 'add_filter('
        );
        
        foreach ($wp_fixes as $wrong => $correct) {
            if (strpos($content, $wrong) !== false) {
                $content = str_replace($wrong, $correct, $content);
                $fixes_applied[] = "修复WordPress函数调用: {$wrong} -> {$correct}";
            }
        }
        
        return $content;
    }
    
    /**
     * 修复常见的PHP问题
     * 
     * @param string $content 文件内容
     * @param array &$fixes_applied 已应用的修复
     * @return string 修复后的内容
     */
    private function fix_common_php_issues($content, &$fixes_applied) {
        // 修复未闭合的PHP标签
        if (strpos($content, '<?php') !== false && strpos($content, '?>') === false) {
            // 这是正常的，PHP文件通常不需要闭合标签
        }
        
        // 修复BOM字符
        if (substr($content, 0, 3) === "\xEF\xBB\xBF") {
            $content = substr($content, 3);
            $fixes_applied[] = "移除BOM字符";
        }
        
        return $content;
    }
    
    /**
     * 验证修复结果
     * 
     * @param string $file_path 文件路径
     * @return array 验证结果
     */
    private function validate_fix($file_path) {
        $output = array();
        $return_var = 0;
        exec("php -l " . escapeshellarg($file_path) . " 2>&1", $output, $return_var);
        
        if ($return_var === 0) {
            return array(
                'valid' => true,
                'message' => '语法检查通过'
            );
        } else {
            return array(
                'valid' => false,
                'error' => implode("\n", $output),
                'message' => '语法检查失败'
            );
        }
    }
    
    /**
     * 恢复备份
     * 
     * @param string $backup_path 备份路径
     * @param string $target_path 目标路径
     * @return bool 是否成功
     */
    public function restore_backup($backup_path, $target_path) {
        if (!file_exists($backup_path)) {
            return false;
        }
        
        if (copy($backup_path, $target_path)) {
            $this->log_backup_restore($backup_path, $target_path);
            return true;
        }
        
        return false;
    }
    
    /**
     * 获取备份列表
     * 
     * @return array 备份列表
     */
    public function get_backup_list() {
        $backups = array();
        
        if (!is_dir($this->backup_dir)) {
            return $backups;
        }
        
        $backup_dirs = glob($this->backup_dir . '/*', GLOB_ONLYDIR);
        
        foreach ($backup_dirs as $backup_dir) {
            $manifest_file = $backup_dir . '/manifest.json';
            if (file_exists($manifest_file)) {
                $manifest = json_decode(file_get_contents($manifest_file), true);
                if ($manifest) {
                    $backups[] = $manifest;
                }
            }
        }
        
        // 按创建时间排序
        usort($backups, function($a, $b) {
            return $b['created_at'] - $a['created_at'];
        });
        
        return $backups;
    }
    
    /**
     * 清理旧备份
     * 
     * @param int $keep_days 保留天数
     * @return int 删除的备份数量
     */
    public function cleanup_old_backups($keep_days = 30) {
        $deleted_count = 0;
        $cutoff_time = time() - ($keep_days * 24 * 3600);
        
        $backup_dirs = glob($this->backup_dir . '/*', GLOB_ONLYDIR);
        
        foreach ($backup_dirs as $backup_dir) {
            $dir_time = filemtime($backup_dir);
            if ($dir_time < $cutoff_time) {
                if ($this->delete_directory($backup_dir)) {
                    $deleted_count++;
                }
            }
        }
        
        return $deleted_count;
    }
    
    /**
     * 递归删除目录
     * 
     * @param string $dir 目录路径
     * @return bool 是否成功
     */
    private function delete_directory($dir) {
        if (!is_dir($dir)) {
            return false;
        }
        
        $files = array_diff(scandir($dir), array('.', '..'));
        
        foreach ($files as $file) {
            $path = $dir . '/' . $file;
            if (is_dir($path)) {
                $this->delete_directory($path);
            } else {
                unlink($path);
            }
        }
        
        return rmdir($dir);
    }
    
    /**
     * 提取行号
     * 
     * @param string $error_message 错误消息
     * @return int 行号
     */
    private function extract_line_number($error_message) {
        if (preg_match('/on line (\d+)/', $error_message, $matches)) {
            return intval($matches[1]);
        }
        return 0;
    }
    
    /**
     * 获取文件指定行内容
     * 
     * @param string $file_path 文件路径
     * @param int $line_number 行号
     * @return string 行内容
     */
    private function get_file_line($file_path, $line_number) {
        if ($line_number <= 0) {
            return '';
        }
        
        $lines = file($file_path, FILE_IGNORE_NEW_LINES);
        return isset($lines[$line_number - 1]) ? $lines[$line_number - 1] : '';
    }
    
    /**
     * 记录备份创建
     * 
     * @param string $original_path 原文件路径
     * @param string $backup_path 备份路径
     */
    private function log_backup_creation($original_path, $backup_path) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log("[WBW_Auto_Fix_Engine] 备份已创建: {$original_path} -> {$backup_path}");
        }
    }
    
    /**
     * 记录备份恢复
     * 
     * @param string $backup_path 备份路径
     * @param string $target_path 目标路径
     */
    private function log_backup_restore($backup_path, $target_path) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log("[WBW_Auto_Fix_Engine] 备份已恢复: {$backup_path} -> {$target_path}");
        }
    }
}